/*
 * Copyright (C) 2008 Esmertec AG.
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.bydavy.android.showsms.transaction;

//~--- non-JDK imports --------------------------------------------------------

import android.app.PendingIntent;

import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;

import android.database.Cursor;
import android.database.sqlite.SQLiteException;

import android.net.Uri;

import android.preference.PreferenceManager;

import android.telephony.gsm.SmsManager;

import android.util.Log;

import com.bydavy.android.showsms.R;
import com.bydavy.android.showsms.util.AppLog;

//~--- JDK imports ------------------------------------------------------------

import java.util.ArrayList;

public class SmsMessageSender {
    //~--- static fields ------------------------------------------------------

    private static final String LOG_TAG                       = AppLog.LOG_TAG;
    private static final boolean DEBUG                        = true;
    public static final String MESSAGE_STATUS_RECEIVED_ACTION =
        "com.android.mms.transaction.MessageStatusReceiver.MESSAGE_STATUS_RECEIVED";
    public static final String MESSAGE_SENT_ACTION          = "com.android.mms.transaction.MESSAGE_SENT";
    public static final String REPLY_PATH_PRESENT           = "reply_path_present";
    public static final String SERVICE_CENTER               = "service_center";
    private static final String[] SERVICE_CENTER_PROJECTION = new String[] { REPLY_PATH_PRESENT, SERVICE_CENTER, };
    private static final int COLUMN_REPLY_PATH_PRESENT      = 0;
    private static final int COLUMN_SERVICE_CENTER          = 1;
    public static final int STATUS_PENDING                  = 64;

    //~--- fields -------------------------------------------------------------

    final String MMS_STATUS_RECEIVED_CLASS_NAME = "com.android.mms.transaction.MessageStatusReceiver";
    final String SMS_RECEIVED_CLASS_NAME        = "com.android.mms.transaction.SmsReceiver";
    private final Context mContext;
    private final int mNumberOfDests;
    private final String[] mDests;
    private final String mMessageText;
    private final String mServiceCenter;
    private final long mThreadId;
    private long mTimestamp;

    //~--- constructors -------------------------------------------------------

    public SmsMessageSender(Context context, String[] dests, String msgText, long threadId) {
        mContext       = context;
        mMessageText   = msgText;
        mNumberOfDests = dests.length;
        mDests         = new String[mNumberOfDests];
        System.arraycopy(dests, 0, mDests, 0, mNumberOfDests);
        mTimestamp     = System.currentTimeMillis();
        mThreadId      = threadId;
        mServiceCenter = getOutgoingServiceCenter(mThreadId);
    }

    //~--- methods ------------------------------------------------------------

    public boolean sendMessage() {
        if ((mMessageText == null) || (mNumberOfDests == 0)) {
            return false;
        }

        SmsManager smsManager = SmsManager.getDefault();

        for (int i = 0; i < mNumberOfDests; i++) {
            ArrayList<String> messages = null;

            messages = smsManager.divideMessage(mMessageText);

            int messageCount = messages.size();

            if (messageCount == 0) {
                return false;
            }

            ArrayList<PendingIntent> deliveryIntents = new ArrayList<PendingIntent>(messageCount);
            ArrayList<PendingIntent> sentIntents     = new ArrayList<PendingIntent>(messageCount);
            SharedPreferences prefs                  = PreferenceManager.getDefaultSharedPreferences(mContext);

            boolean requestDeliveryReport_def        = Boolean.valueOf(mContext.getString(R.preferences.sms_ack_def));
            boolean requestDeliveryReport            = prefs.getBoolean(mContext.getString(R.preferences.sms_ack_key),
                                                           requestDeliveryReport_def);
            Uri uri = null;

            try {
                uri = addMessage(mContext.getContentResolver(), mDests[i], mMessageText, null, mTimestamp,
                                 requestDeliveryReport, mThreadId);
            } catch (SQLiteException e) {
            	Log.e(LOG_TAG, "Error adding message");
            }

            for (int j = 0; j < messageCount; j++) {
                if (requestDeliveryReport) {

                    deliveryIntents.add(PendingIntent.getBroadcast(mContext, 0,
                            new Intent(MESSAGE_STATUS_RECEIVED_ACTION, uri).setClassName(mContext,
                                       MMS_STATUS_RECEIVED_CLASS_NAME), 0));
                }

                sentIntents.add(PendingIntent.getBroadcast(mContext, 0,
                        new Intent(MESSAGE_SENT_ACTION, uri).setClassName(mContext, SMS_RECEIVED_CLASS_NAME), 0));
            }

            if (DEBUG) {
                Log.v(LOG_TAG,
                      "sendMessage: address[" + i + "]=" + mDests[i] + ", threadId=" + mThreadId + ", uri=" + uri
                      + ", msgs.count=" + messageCount);
            }

            try {
                smsManager.sendMultipartTextMessage(mDests[i], mServiceCenter, messages, sentIntents, deliveryIntents);
            } catch (Exception ex) {
                return false;
            }
        }

        return false;
    }

    //~--- get methods --------------------------------------------------------

    /**
     * Get the service center to use for a reply.
     *
     * The rule from TS 23.040 D.6 is that we send reply messages to
     * the service center of the message to which we're replying, but
     * only if we haven't already replied to that message and only if
     * <code>TP-Reply-Path</code> was set in that message.
     *
     * Therefore, return the service center from the most recent
     * message in the conversation, but only if it is a message from
     * the other party, and only if <code>TP-Reply-Path</code> is set.
     * Otherwise, return null.
     */
    private String getOutgoingServiceCenter(long threadId) {
        Cursor cursor = null;

        try {
            cursor = mContext.getContentResolver().query(Uri.parse("content://sms"), SERVICE_CENTER_PROJECTION,
                    "thread_id = " + threadId, null, "date DESC");

            if ((cursor == null) ||!cursor.moveToFirst()) {
                return null;
            }

            boolean replyPathPresent = (1 == cursor.getInt(COLUMN_REPLY_PATH_PRESENT));

            return replyPathPresent ? cursor.getString(COLUMN_SERVICE_CENTER) : null;
        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }
    }

    //~--- methods ------------------------------------------------------------

    public static Uri addMessageToUri(ContentResolver resolver, Uri uri, String address, String body, String subject,
                                      Long date, boolean read, boolean deliveryReport, long threadId) {
        ContentValues values = new ContentValues(7);

        values.put("address", address);

        if (date != null) {
            values.put("date", date);
        }

        values.put("read", read ? Integer.valueOf(1) : Integer.valueOf(0));
        values.put("subject", subject);
        values.put("body", body);

        if (deliveryReport) {
            values.put("status", STATUS_PENDING);
        }

        if (threadId != -1L) {
            values.put("thread_id", threadId);
        }

        return resolver.insert(uri, values);
    }

    public static Uri addMessage(ContentResolver resolver, String address, String body, String subject, Long date,
                                 boolean deliveryReport, long threadId) {
        return addMessageToUri(resolver, Uri.parse("content://sms/outbox"), address, body, subject, date, true,
                               deliveryReport, threadId);
    }
}
